package com.aabte.permissionframeworklearn.permission.service;

import com.aabte.permissionframeworklearn.permission.beans.CacheKeyConstants;
import com.aabte.permissionframeworklearn.permission.common.RequestHolder;
import com.aabte.permissionframeworklearn.permission.mapper.SysAclMapper;
import com.aabte.permissionframeworklearn.permission.mapper.SysRoleAclMapper;
import com.aabte.permissionframeworklearn.permission.mapper.SysUserRoleMapper;
import com.aabte.permissionframeworklearn.permission.model.SysAcl;
import com.aabte.permissionframeworklearn.permission.model.SysUser;
import com.aabte.permissionframeworklearn.permission.util.JsonMapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author Daniel
 */
@Service
public class SysCoreService {

    @Autowired
    private SysAclMapper sysAclMapper;

    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Autowired
    private SysRoleAclMapper sysRoleAclMapper;

    @Autowired
    private SysCacheService sysCacheService;

    public List<SysAcl> getCurrentUserAclList() {
        Long userId = RequestHolder.getCurrentUser().getId();
        return getUserAclList(userId);
    }

    public List<SysAcl> getRoleAclList(Long roleId) {
        List<Long> aclIdList = sysRoleAclMapper.getAclIdListByRoleIdList(Lists.newArrayList(roleId));
        if (CollectionUtils.isEmpty(aclIdList)) {
            return Lists.newArrayList();
        }
        List<SysAcl> sysAclList = sysAclMapper.getByIdList(aclIdList);
        return sysAclList;
    }

    public List<SysAcl> getUserAclList(Long userId) {
        if (isSuperAdmin()) {
            return sysAclMapper.getAll();
        }
        List<Long> userRoleIdList = sysUserRoleMapper.getRoleIdListByUserId(userId);
        if (CollectionUtils.isEmpty(userRoleIdList)) {
            return Lists.newArrayList();
        }

        List<Long> userAclIdList = sysRoleAclMapper.getAclIdListByRoleIdList(userRoleIdList);
        if (CollectionUtils.isEmpty(userAclIdList)) {
            return Lists.newArrayList();
        }

        List<SysAcl> sysAclList = sysAclMapper.getByIdList(userAclIdList);
        return sysAclList;
    }

    private boolean isSuperAdmin() {
        SysUser currentUser = RequestHolder.getCurrentUser();
        if (StringUtils.startsWith(currentUser.getUsername(), "admin@")
                || "admin".equals(currentUser.getUsername())) {
            return true;
        }
        return false;
    }

    public boolean hasUrlAcl(String servletPath) {
        if (isSuperAdmin()) {
            return true;
        }
        List<SysAcl> acls = sysAclMapper.getByUrl(servletPath);
        if (CollectionUtils.isEmpty(acls)) {
            // 此接口无需权限
            return true;
        }

        List<SysAcl> userAclList = getCurrentUserAclListFromCache();
        Set<Long> userAclIdSet = userAclList.stream().map(SysAcl::getId).collect(Collectors.toSet());

        // 记录是否有校验过权限
        boolean hasValidAcl = false;
        // 只要有一个权限点有权限，就认为有访问权限
        for (SysAcl acl : acls) {
            // 当权限状态为无效
            if (null == acl || acl.getStatus() != 1) {
                continue;
            }
            // 标记有核验过权限
            hasValidAcl = true;
            if (userAclIdSet.contains(acl.getId())) {
                // 拥有权限
                return true;
            }
        }
        if (!hasValidAcl) {
            // 没有校验过权限，表示该接口无需权限校验
            return true;
        }
        // 无权限访问
        return false;
    }

    public List<SysAcl> getCurrentUserAclListFromCache() {
        SysUser currentUser = RequestHolder.getCurrentUser();
        String cacheValue = sysCacheService.getFromCache(
                CacheKeyConstants.USER_ACLS,
                String.valueOf(currentUser.getId()));
        if (StringUtils.isBlank(cacheValue)) {
            List<SysAcl> aclList = getCurrentUserAclList();
            if (CollectionUtils.isNotEmpty(aclList)) {
                sysCacheService.saveCache(
                        JsonMapper.obj2String(aclList),
                        600,
                        CacheKeyConstants.USER_ACLS,
                        String.valueOf(currentUser.getId()));
            }
            return aclList;
        } else {
            List<SysAcl> aclList = JsonMapper.string2Obj(cacheValue, new TypeReference<List<SysAcl>>() {
            });
            return aclList;
        }
    }
}
